/**
 * Copyright (C) 2009 Matteo Merli <mm@merlimat.org>
 * 
 * $Id: ComparisonTree.java 23 2009-01-14 16:45:36Z matteo.merli $
 * $URL: http://pxl-lang.googlecode.com/svn/trunk/src/main/java/pxl/types/util/ComparisonTree.java $
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *         http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package pxl.types.util;

import java.util.List;

import org.antlr.runtime.CommonToken;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.antlr.runtime.tree.TreeNodeStream;

import pxl.grammar.classes.PxlParser;
import pxl.grammar.classes.PxlTreeWalker;
import pxl.types.None;
import pxl.types.PxlBoolean;
import pxl.types.PxlObject;

import com.google.common.collect.Lists;

public class ComparisonTree extends CommonTree
{
    private final List<ComparisonOperator> operators;
    private final List<CommonTree> expressions;

    public ComparisonTree( CommonTree left,
            List<CommonTree> right, List<ComparisonOperator> operators )
    {
        super( new CommonToken( PxlParser.COMPARISON, "COMPARISON" ) );
        this.operators = operators;
        expressions = Lists.newArrayListWithExpectedSize( right.size() + 1 );
        expressions.add( left );
        expressions.addAll( right );
    }

    public PxlBoolean evaluate()
    {
        int i = 0;

        PxlObject left = evaluate( expressions.get( 0 ) );
        PxlObject right = left;

        for ( ComparisonOperator op : operators )
        {
            left = right;
            right = evaluate( expressions.get( i + 1 ) );

            PxlBoolean res = evaluate( left, right, op );
            if ( res == PxlBoolean.False )
                return PxlBoolean.False;

            ++i;
        }

        return PxlBoolean.True;
    }

    private PxlBoolean evaluate( PxlObject a, PxlObject b, ComparisonOperator op )
    {
        switch ( op )
        {
        case Less:
            return a.__lt__( b );
        case LessEqual:
            return a.__lte__( b );
        case Greater:
            return a.__gt__( b );
        case GreaterEqual:
            return a.__gt__( b );
        case Equal:
            return a.__eq__( b );
        case NotEqual:
            return a.__neq__( b );
        case In:
            return b.__contains__( a );
        case NotIn:
            return PxlBoolean.not( b.__contains__( a ) );

        case Is:
        case IsNot:
        default:
            return PxlBoolean.False;
        }
    }

    private PxlObject evaluate( CommonTree expr )
    {
        TreeNodeStream stream = new CommonTreeNodeStream( expr );
        PxlTreeWalker treeWalker = new PxlTreeWalker( stream );

        try
        {
            return treeWalker.expr();
        }
        catch ( RecognitionException e )
        {
            e.printStackTrace();
            return None.instance();
        }
    }
}
